package com.yjb.tenet.boot.system.application.manager;

import cn.hutool.core.util.ObjectUtil;
import com.yjb.tenet.boot.common.constants.GlobalConstants;
import com.yjb.tenet.boot.system.application.checker.SysDicDataChecker;
import com.yjb.tenet.boot.system.application.convert.SysDicDataConvert;
import com.yjb.tenet.boot.system.application.service.SysDicDataService;
import com.yjb.tenet.boot.system.domain.dto.SysDicDataDTO;
import com.yjb.tenet.boot.system.domain.entity.SysDicData;
import com.yjb.tenet.boot.system.domain.form.SysDicDataAddForm;
import com.yjb.tenet.boot.system.domain.form.SysDicDataEditForm;
import com.yjb.tenet.boot.system.infrastructure.constant.SysRedisKeyConstants;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 字典项/字典数据
 * @Author 贾栋栋
 * @Date 2023/3/8 11:51
 **/
@Component
public class SysDicDataManager {

    @Resource
    private SysDicDataService sysDicDataService;

    @Resource
    private SysDicDataChecker sysDicDataChecker;

    @Resource
    private RedisTemplate redisTemplate;


    /**
     * 创建字典项
     */
    @Transactional(rollbackFor = Exception.class)
    public void add(SysDicDataAddForm form) {
        sysDicDataChecker.checkForExist(null, form.getDicCode(), form.getDicValue(), form.getDicLabel());

        SysDicData convert = SysDicDataConvert.INSTANCE.convert(form);
        sysDicDataService.save(convert);
        redisTemplate.delete(SysRedisKeyConstants.SYS_DIC_KEY_ITEM + form.getDicCode());
        redisTemplate.delete(SysRedisKeyConstants.SYS_DIC_KEY_ALL);
    }

    /**
     * 编辑
     */
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysDicDataEditForm form) {
        sysDicDataChecker.checkForExist(form.getId(), null, form.getDicValue(), form.getDicLabel());

        SysDicData convert = SysDicDataConvert.INSTANCE.convert(form);
        sysDicDataService.updateById(convert);

        SysDicData byId = sysDicDataService.getById(form.getId());
        redisTemplate.delete(SysRedisKeyConstants.SYS_DIC_KEY_ITEM + byId.getDicCode());
        redisTemplate.delete(SysRedisKeyConstants.SYS_DIC_KEY_ALL);
    }

    /**
     * 删除
     */
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        SysDicData sysDicData = sysDicDataService.getById(id);
        sysDicData.setId(id);
        sysDicData.setDeleted(id);
        sysDicDataService.updateById(sysDicData);

        redisTemplate.delete(SysRedisKeyConstants.SYS_DIC_KEY_ITEM + sysDicData.getDicCode());
        redisTemplate.delete(SysRedisKeyConstants.SYS_DIC_KEY_ALL);
    }


    /**
     * 刷新缓存
     */
    public void refresh() {
        Map<String, List<SysDicDataDTO>> dicMap = new HashMap<>();

        List<SysDicData> list = sysDicDataService.lambdaQuery()
                .eq(SysDicData::getDeleted, GlobalConstants.NOT_DELETED)
                .orderByAsc(SysDicData::getDicCode, SysDicData::getOrderNo).list();

        List<SysDicDataDTO> convert = SysDicDataConvert.INSTANCE.convertDTO(list);

        convert.stream().forEach(sysDicDataDTO -> {
                // 创建字典项对象
                // 如果该字典项还未创建，则新增
                if(!dicMap.containsKey(sysDicDataDTO.getDicCode())){
                    dicMap.put(sysDicDataDTO.getDicCode(), new ArrayList<>());
                }
                // 向字典中加入新的字典项
                dicMap.get(sysDicDataDTO.getDicCode()).add(sysDicDataDTO);
        });

        Set keys = redisTemplate.keys(SysRedisKeyConstants.SYS_DIC_KEY + "*");
        redisTemplate.delete(keys);
        dicMap.keySet().forEach(dicCode->{
            List<SysDicDataDTO> dicItemList = dicMap.get(dicCode);
            redisTemplate.opsForValue().set(SysRedisKeyConstants.SYS_DIC_KEY_ITEM + dicCode, dicItemList);
        });

        redisTemplate.opsForValue().set(SysRedisKeyConstants.SYS_DIC_KEY_ALL , convert);
    }

    /**
     * 查询全部的字典数据
     * @return
     */
    public List<SysDicDataDTO> list() {
        // 先从缓存中查
        List<SysDicDataDTO> cacheList = (List<SysDicDataDTO>) redisTemplate.opsForValue().get(SysRedisKeyConstants.SYS_DIC_KEY_ALL);

        // 查不到再从数据库中查
        if(ObjectUtil.isNull(cacheList)){
            List<SysDicData> list = sysDicDataService.lambdaQuery()
                    .eq(SysDicData::getDeleted, GlobalConstants.NOT_DELETED)
                    .orderByAsc(SysDicData::getDicCode, SysDicData::getOrderNo)
                    .list();
            cacheList = SysDicDataConvert.INSTANCE.convertDTO(list);

            // 查完存入缓存
            redisTemplate.opsForValue().set(SysRedisKeyConstants.SYS_DIC_KEY_ALL , cacheList);
        }

        return cacheList;
    }

    /**
     * 根据字典CODE查询值
     */
    public List<SysDicDataDTO> getItemByCode(String dicCode){

        // 先从缓存中查
        List<SysDicDataDTO> cacheList = (List<SysDicDataDTO>) redisTemplate.opsForValue().get(SysRedisKeyConstants.SYS_DIC_KEY + dicCode);

        // 查不到再从数据库中查
        if(ObjectUtil.isNull(cacheList)){
            List<SysDicData> list = sysDicDataService.lambdaQuery()
                    .eq(SysDicData::getDeleted, GlobalConstants.NOT_DELETED)
                    .eq(SysDicData::getDicCode, dicCode)
                    .orderByAsc(SysDicData::getOrderNo)
                    .list();
            cacheList = SysDicDataConvert.INSTANCE.convertDTO(list);

            redisTemplate.opsForValue().set(SysRedisKeyConstants.SYS_DIC_KEY_ITEM + dicCode, cacheList);
        }
        return cacheList;
    }

    /**
     * 获取单个CODE的Map集合
     * @param dicCode
     * @return
     */
    public Map<String, String> getItemMapByCode(String dicCode){
        List<SysDicDataDTO> itemByCode = getItemByCode(dicCode);
        Map<String, String> map = itemByCode.stream().collect(Collectors.toMap(SysDicDataDTO::getDicValue, SysDicDataDTO::getDicLabel));
        return map;
    }


    /**
     * 获取字典数据
     * @param code 字典code
     * @param value 字典value
     */
    public SysDicDataDTO getDictData(String code, String value) {
        SysDicData one = sysDicDataService.lambdaQuery()
                .eq(SysDicData::getDeleted, GlobalConstants.NOT_DELETED)
                .eq(SysDicData::getDicCode, code)
                .eq(SysDicData::getDicValue, value)
                .one();
        return SysDicDataConvert.INSTANCE.convert(one);
    }

    /**
     * 根据code label 查询 value
     * @param code 字典编码
     * @param label 字典标签
     * @return
     */
    public SysDicDataDTO parseDictData(String code, String label) {
        SysDicData one = sysDicDataService.lambdaQuery()
                .eq(SysDicData::getDeleted, GlobalConstants.NOT_DELETED)
                .eq(SysDicData::getDicCode, code)
                .eq(SysDicData::getDicLabel, label)
                .one();

        return SysDicDataConvert.INSTANCE.convert(one);
    }
}
